/*
	File:		Game.cpp
	Course:		SGD 1301
	Author:		Peter Nguyen
	Purpose:	CGame class controls the SGD Wrappers
				and the game logic
*/

#include "Game.h"

#include "../SGD Wrappers/CSGD_Direct3D.h"
#include "../SGD Wrappers/CSGD_DirectInput.h"
#include "../SGD Wrappers/CSGD_TextureManager.h"
#include "../SGD Wrappers/CSGD_XAudio2.h"

#include "BitmapFont.h"

#include "IGameState.h"
#include "MainMenuState.h"

#include <cassert>

#include <iostream>
#include <fstream>

bool CGame::DEBUG_MODE = false;

////////////////////////////////////////////////////////////
// Instantiate the static data member
/*static*/ CGame*	CGame::s_pInstance	= nullptr;

// GetInstance		- create the object
/*static*/ CGame*	CGame::GetInstance( void )
{
	if( s_pInstance == nullptr )
		s_pInstance = new CGame;

	return s_pInstance;
}

// DeleteInstance	- deallocate the object
/*static*/ void		CGame::DeleteInstance( void )
{
	delete s_pInstance;
	s_pInstance = nullptr;
}




////////////////////////////////////////////////////////////
// CONSTRUCTOR
CGame::CGame(void)
{
	// Set the data members to 'clean' values
	m_pD3D			= nullptr;
	m_pDI			= nullptr;
	m_pTM			= nullptr;
	m_pXA			= nullptr;
	m_pFont			= nullptr;

	
	m_nScreenWidth	= 1;
	m_nScreenHeight	= 1;
	m_bIsWindowed	= true;
	m_bIsFullscreen = 0;

	m_dwCurrTime	= 0;
		
	m_pCurrState	= nullptr;

	m_nScore = 0;
}


////////////////////////////////////////////////////////////
// DESTRUCTOR
CGame::~CGame(void)
{
	/* do nothing yet */
}



////////////////////////////////////////////////////////////
// Initialize	- setup the game
void CGame::Initialize( HWND hWnd, HINSTANCE hInstance,
					int nWidth, int nHeight, bool bIsWindowed )
{
	// Store the wrapper singletons
	m_pD3D			= CSGD_Direct3D::GetInstance();
	m_pDI			= CSGD_DirectInput::GetInstance();
	m_pTM			= CSGD_TextureManager::GetInstance();
	m_pXA			= CSGD_XAudio2::GetInstance();

	m_pFont			= new CBitmapFont;

	
	// Store the parameters
	m_nScreenWidth	= nWidth;
	m_nScreenHeight	= nHeight;
	m_bIsWindowed	= bIsWindowed;

	// Initialize the wrappers
	m_pD3D->InitDirect3D( hWnd, nWidth, nHeight, bIsWindowed, false );
	m_pDI->InitDirectInput( hWnd, hInstance, DI_KEYBOARD /*| DI_MOUSE | DI_JOYSTICKS*/ );
	m_pTM->InitTextureManager( m_pD3D->GetDirect3DDevice(), m_pD3D->GetSprite() );
	m_pXA->InitXAudio2();
	m_pFont->Initialize();
	
	
	m_dwCurrTime	= GetTickCount();	// milliseconds

	
	std::ifstream myFile;
	myFile.open("settings.txt");
	int nSFX = 100;
	int nBGM = 100;
	if(myFile.is_open())
	{
		myFile >> nSFX;
		myFile >> nBGM;
		myFile.close();
	}
	SetSoundVolume(nSFX);
	SetBGMVolume(nBGM);
	// Start in the MainMenu state
	PushState( CMainMenuState::GetInstance() );
}


////////////////////////////////////////////////////////////
// Main			- play one frame of the game
bool CGame::Main( void )
{
	// Handle input
	if( Input() == false )
		return false;

	// Update & render game entities
	Update();
	Render();

	return true;
}


////////////////////////////////////////////////////////////
// Shutdown		- cleanup the game
void CGame::Shutdown( void )
{
	if( m_pCurrState != nullptr )
		m_pCurrState->Exit();
	m_pCurrState = nullptr;
	while(m_sStateStack.size()>0)
	{
		if(m_sStateStack.top()!=nullptr)
			m_sStateStack.top()->Exit();
		m_sStateStack.pop();
	}

	// Shutdown the wrappers in REVERSE order
	if( m_pFont != nullptr )
	{
		m_pFont->Shutdown();
		delete m_pFont;
		m_pFont = nullptr;
	}

	if( m_pXA != nullptr )
	{
		m_pXA->ShutdownXAudio2();
		m_pXA = nullptr;
	}

	if( m_pTM != nullptr )
	{
		m_pTM->ShutdownTextureManager();
		m_pTM = nullptr;
	}

	if( m_pDI != nullptr )
	{
		m_pDI->ShutdownDirectInput();
		m_pDI = nullptr;
	}

	if( m_pD3D != nullptr )
	{
		m_pD3D->ShutdownDirect3D();
		m_pD3D = nullptr;
	}
}


////////////////////////////////////////////////////////////
// Input		- process user input
bool CGame::Input ( void )
{
	// Read the input devices
	m_pDI->ReadDevices();


	// Let the state read input
	return m_pCurrState->Input();
}

bool CGame::CheckToggleFullScreen()
{
	return(m_pDI->KeyDown(DIK_LALT) && m_pDI->KeyPressed(DIK_RETURN));
}

////////////////////////////////////////////////////////////
// Update		- update the game entities
void CGame::Update( void )
{
	// Refresh the audio
	m_pXA->Update();


	// Calculate the elapsed time between frames
	DWORD dwNow = GetTickCount();
	float fElapsedTime = (dwNow - m_dwCurrTime) / 1000.0f;
	m_dwCurrTime = dwNow;


	if( fElapsedTime > 0.125 )
		fElapsedTime = 0.125;


	// Update the current state
	m_pCurrState->Update( fElapsedTime );
}

////////////////////////////////////////////////////////////
// Render		- render the game entities
void CGame::Render( void )
{
	// Clear the background
	CSGD_Direct3D::GetInstance()->Clear( 0,0,0);

	// Start the rendering
	m_pD3D->DeviceBegin();
	m_pD3D->SpriteBegin();



	// Render the current state
	m_pCurrState->Render();



	// End the rendering
	m_pD3D->SpriteEnd();
	m_pD3D->DeviceEnd();

	// Present the backbuffer to the screen
	m_pD3D->Present();
}

void CGame::PushState( IGameState* pNewState)
{
	if(m_pCurrState!=nullptr)
		m_sStateStack.push(m_pCurrState);
	m_pCurrState = pNewState;
	if(m_pCurrState!= nullptr)
		m_pCurrState->Enter();
}

void CGame::PopState( )
{
	if( m_pCurrState != nullptr )
		m_pCurrState->Exit();

	if(m_sStateStack.size()==0)
		return;

	m_pCurrState = m_sStateStack.top();
		m_sStateStack.pop();
}

IGameState*	 CGame::TopState()
{
	if(m_sStateStack.size()==0)
		return nullptr;
	return m_sStateStack.top();
}

//// Game State Machine
//void CGame::ChangeState( IGameState* pNewState )
//{
//	// Exit the current state (if any)
//	if( m_pCurrState != nullptr )
//		m_pCurrState->Exit();
//
//
//	// Store the new state
//	m_pCurrState = pNewState;
//
//
//	// Enter the new state (if any)
//	if( m_pCurrState != nullptr )
//		m_pCurrState->Enter();
//}

	void CGame::SetSoundVolume( int SoundVolume	)	
	{	
		m_bSoundVolume		= SoundVolume	;
		if(m_bSoundVolume<0)
			m_bSoundVolume = 0;
		else if(m_bSoundVolume>100)
			m_bSoundVolume = 100;
	}
	void CGame::SetBGMVolume( int BGMVolume	)	
	{	
		m_bBGMVolume		= BGMVolume	;
		if(m_bBGMVolume<0)
			m_bBGMVolume = 0;
		else if(m_bBGMVolume>100)
			m_bBGMVolume = 100;
	}
	
	
	void CGame::ChangeScore( int Change )
	{
		m_nScore += Change;
		if(m_nScore <= 0)
			m_nScore = 0;
	}